package errgrouplearn

import (
	"context"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"golang.org/x/sync/errgroup"
)

func Run() {

	ctx, cancel := context.WithCancel(context.Background())
	// 下面的 cancel 取消的是 顶层的 ctx，
	// callRun函数中的代码可以看到，其中用的是errgroup.WithContext 返回的子ctx

	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, os.Interrupt, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM)

	go func() {
		<-sigChan
		log.Println("Shutdown signal received")
		// do clear fun
		cancel() //kill 会走到这，取消最顶层 ctx，进而 client.Run 中几个go程监控的 子ctx也会被取消
		//测试日志
		//2025/07/01 17:41:58 go 1 default run
		//2025/07/01 17:42:01 go 2 ticker run
		//2025/07/01 17:42:02 Shutdown signal received
		//2025/07/01 17:42:02 go 2 ctx.Done case run
		//2025/07/01 17:42:02 go 3 ctx.Done case run
		//2025/07/01 17:42:03 go 1 default run
		//2025/07/01 17:42:03 go 1 ctx.Done case run
	}()
	callRun(ctx) // 会卡住于 errgroup.Wait()
	cancel()

}

// 运行机器人主循环
func callRun(ctx context.Context) error {

	g, ctx := errgroup.WithContext(ctx)
	// 后面的ctx都是新赋值的子 ctx了

	// 消息接收协程
	g.Go(func() error {
		for {
			select {
			case <-ctx.Done():
				log.Printf("go 1 ctx.Done case run")
				return nil
			default:
				time.Sleep(time.Second * 5)
				log.Printf("go 1 default run")
			}
		}
	})

	// 心跳协程
	g.Go(func() error {
		ticker := time.NewTicker(3 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ctx.Done():
				log.Printf("go 2 ctx.Done case run")
				return nil
			case <-ticker.C:
				log.Printf("go 2 ticker run")
			}
		}
	})

	// 状态报告协程
	g.Go(func() error {
		ticker := time.NewTicker(60 * time.Second)
		defer ticker.Stop()

		for {
			select {
			case <-ctx.Done():
				log.Printf("go 3 ctx.Done case run")
				return nil
			case <-ticker.C:
				log.Printf("go 3 ticker run")
			}
		}
	})

	//<-ctx.Done() // 没必要单纯的对group中的 ctx做 Done检查，有Wait就够了
	//可能的场景，是业务上需要综合 ctx.Done() 和其他等待，共同组合的 select 语句块。但那是业务的综合需求了

	return g.Wait()
}
